package com.dldata.devtools30.controller.si;

/**
 * Created by ai on 2017/1/11.
 */


import com.alibaba.fastjson.JSON;
import com.dldata.devtools30.businessmodel.SessionUserInfoEntity;
import com.dldata.devtools30.controller.DevBase30Controller;
import com.dldata.devtools30.entity.DevtApiLogEntity;
import com.dldata.devtools30.entity.DevtApiSubEntity;
import com.dldata.devtools30.entity.DevtApiTjoptEntity;
import com.dldata.devtools30.service.api.DevtApiMainEntityService;
import com.dldata.devtools30.service.api.DevtApiSubEntityService;
import com.dldata.devtools30.service.api.DevtApiTjoptEntityService;
import com.dldata.devtools30.utils.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Timestamp;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.dldata.devtools30.utils.Util.DEVTOOLUSER;


/**

 * 将请求的commonApi与管理的Controller分开
 */
@Controller
@RequestMapping(value = "/ApiUpdateService")
@Slf4j
public class ApiUpdateServiceController extends DevBase30Controller {
    
    @Autowired
    private DevtApiTjoptEntityService devtApiTjoptEntityService;
    
    @Autowired
    private DevtApiSubEntityService devtApiSubEntityService;
    
    @Autowired
    private DevtApiMainEntityService apiMainEntityService;
    
    /**
     * token 校验后台请求
     * 1.校验参数并解析出功能对象和分页数据
     * 1.1.假如传pid就以pid为准,查询出DevtApiSubEntity,假如查询出来查询出DevtApiSubEntity,直接使用第一个,忽略mid和dm
     * 1.2.第一步没有查询出DevtApiSubEntity,使用mid和dm查询DevtApiSubEntity,假如查询出来查询出DevtApiSubEntity,直接使用第一个
     * 1.3.第二步没有查询出DevtApiSubEntity,使用dm查询DevtApiSubEntity,假如查询出来查询出DevtApiSubEntity,直接使用第一个
     *
     * 2.逐个执行SQL并获取结果和总页数
     *
     * 3.依据结果组装返回JSON
     *
     * 4.记录接口日志
     *
     * @param request
     * @param res
     * @return
     */
    @RequestMapping(value = "")
    @ResponseBody
    public Object apiexec(
            HttpServletRequest request, HttpServletResponse res,@RequestParam Map<String, Object> paramMap) throws IOException {
   
        BufferedReader reader=new BufferedReader(new InputStreamReader(request.getInputStream(),"UTF-8"));
        StringBuilder jsonStringBuilder= new StringBuilder();
        String tmpStr=null;
        while ((tmpStr=reader.readLine())!=null){
            jsonStringBuilder.append(tmpStr);
        }
        Map<String, Object> jsonMap = new HashMap<>(paramMap);
        if(jsonStringBuilder.toString().length()>0&&jsonStringBuilder.toString().startsWith("{")){
            Map<String, Object> bodyJsonMap= JSON.parseObject(jsonStringBuilder.toString(), Map.class);
            jsonMap.putAll(bodyJsonMap);
            log.debug("request jsonbody："+jsonStringBuilder);
        }
        DevtApiSubEntity devtApiSubEntity=getDevtApiSubEntity(jsonMap.getOrDefault("p_id","").toString() ,jsonMap.getOrDefault("p_dm","").toString());
        if(devtApiSubEntity==null){
            HashMap resultMap= new HashMap();
            resultMap.put("success",Boolean.FALSE);
            resultMap.put("msg","未查询到API:"+request.getParameter("p_dm"));
            return resultMap;
        }
    
        try {
            List<Map> hashMapDataList=new ArrayList<>();
            if(jsonMap.get("data") instanceof Map){
                hashMapDataList.add((Map)jsonMap.get("data"));
            }
            //多行数据
            if(jsonMap.get("data") instanceof List){
                hashMapDataList.addAll((List)jsonMap.get("data"));
            }
            for (int i = 0; i < hashMapDataList.size(); i++) {
                Map jsonMapOne = hashMapDataList.get(i);
                HashMap resultMap = checkJsonMapData(request, devtApiSubEntity, jsonMapOne);
                if(resultMap!=null){
                    return resultMap;
                }
            }
    
            List<SqlAndParameters> sqlAndParametersList=new ArrayList<>();
            for (int i = 0; i < hashMapDataList.size(); i++) {
                Map jsonMapOne =  hashMapDataList.get(i);
                SqlAndParameters sqlAndParameterses = getExcuteSql(request, devtApiSubEntity,jsonMapOne);
                sqlAndParametersList.add(sqlAndParameterses);
            }
    
            SqlAndParameters sqlAndParametersCurrent=null;
            try {
                for (int i = 0; i < sqlAndParametersList.size(); i++) {
                    sqlAndParametersCurrent = sqlAndParametersList.get(i);
                    execSql(devtApiSubEntity, sqlAndParametersCurrent);
                }
                saveExecLog(devtApiSubEntity,jsonMap, sqlAndParametersCurrent, "", "0", "");
                HashMap resultJson1= new HashMap();
                resultJson1.put("success",true);
                resultJson1.put("msg", "更新成功.");
                return resultJson1;
            }catch (Throwable throwable){
                log.error(throwable.getMessage(),throwable);
                saveExecLog(devtApiSubEntity,jsonMap, sqlAndParametersCurrent, throwable.getMessage(), "1", throwable.getMessage());
                HashMap resultMap= new HashMap();
                resultMap.put("success",false);
                resultMap.put("msg","系统错误，请稍候再试::"+throwable.getMessage());
                return resultMap;
            }
        } catch (Exception ex) {
            log.error(ex.getMessage(),ex);
            saveExecLog(devtApiSubEntity,jsonMap, null, ex.getMessage(), "1", ex.getMessage());
            HashMap resultMap= new HashMap();
            resultMap.put("success",false);
            resultMap.put("msg","系统错误，请稍候再试::"+ex.getMessage());
            return resultMap;
        }
        

   
    }
    
    protected HashMap checkJsonMapData(HttpServletRequest request, DevtApiSubEntity devtApiSubEntity, Map<String, Object> jsonMap){
        
        List<DevtApiTjoptEntity> optlist =devtApiTjoptEntityService.getAllDataByIdOrDm(devtApiSubEntity.getId());
    
        List validateResult = new LinkedList<>();
        if(DevtApiSubEntityService.sqltype.replaceconcat.name().equalsIgnoreCase(devtApiSubEntity.getSqltype())){
            final Pattern sqlPattern = Pattern.compile(Public.sqlZhuru, Pattern.CASE_INSENSITIVE);
            optlist.forEach(
                    apiTjoptEntity -> {
                        String argValueOrg = StringUtil.isNullOrSpace(request.getParameter(apiTjoptEntity.getArgname())) ? "" : StringUtil.unescape(request.getParameter(apiTjoptEntity.getArgname()));
                        String argsPost = StringUtil.isEmptyOrLength0(jsonMap.get(apiTjoptEntity.getArgname())) ? "" : jsonMap.get(apiTjoptEntity.getArgname()).toString();
                        argValueOrg=StringUtil.isEmptyOrLength0(argValueOrg)? argsPost :argValueOrg;
                        if(sqlPattern.matcher(argValueOrg).find()){
                            HashMap hashMap = new HashMap();
                            hashMap.put("errorinfo","参数非法");
                            hashMap.put("fieldName",apiTjoptEntity.getArgname());
                            validateResult.add(hashMap);
                        }
                    }
            );
        }
    
        if(validateResult.size()>0){
            HashMap resultMap= new HashMap();
            resultMap.put("success",validateResult.size()==0);
            resultMap.put("resultdata",validateResult);
            resultMap.put("msg",validateResult);
            return resultMap;
        }
    
        return null;
    }

    protected HashMap execSql(DevtApiSubEntity devtApiSubEntity, SqlAndParameters sqlAndParameters) {
        
        switch(DevtApiMainEntityService.FunctionType.valueOf(devtApiSubEntity.getLx())){
            case POSTJSON:{
                execUpdateFunction(devtApiSubEntity, sqlAndParameters);
                HashMap resultJson1= new HashMap();
                resultJson1.put("success",true);
                resultJson1.put("msg", "更新成功.");
                return resultJson1;
            }
            default:{
                HashMap resultMap= new HashMap();
                resultMap.put("success",false);
                resultMap.put("msg","API类型有误");
                return resultMap;
            }
        }
    }
    
    private Object execUpdateFunction( DevtApiSubEntity devtApiSubEntity, SqlAndParameters func_SqlAry) {
        final List<Object> returnData = new LinkedList<>();
        final List<Integer> returnDataTotalCount = new LinkedList<Integer>();
        if(DevtApiSubEntityService.sqltype.nameprecompile.name().equals(devtApiSubEntity.getSqltype())){
            MapSqlParameterSource parameters = new MapSqlParameterSource();
            for (int j = 0; j < func_SqlAry.parameters.length; j++) {
                parameters.addValue( func_SqlAry.parametersNames[j], func_SqlAry.parameters[j]);
            }
            log.info("sql: "+ func_SqlAry.sql.trim());
            log.info("argsNames: "+StringUtil.arrayToCommaDelimitedString(func_SqlAry.parametersNames));
            log.info("args: "+StringUtil.arrayToCommaDelimitedString(func_SqlAry.parameters));
            int numcount= nbjdbcTemplate.update(func_SqlAry.sql.trim(),parameters);
            returnData.add(numcount);
            returnDataTotalCount.add(numcount);
        }else{
            int numcount= jdbcTemplate.update(func_SqlAry.sql.trim(),func_SqlAry.parameters);
            returnData.add(numcount);
            returnDataTotalCount.add(numcount);
        }
    
        Map<String,Object> dataMap = new HashMap<>();

        return dataMap;
    }
    
    
    /**
     * 记录日志 后面可以考虑写文件 已完成
     * @param pFunctionsubEntity
     * @param sqlAndParameters
     * @param resultJson
     * @param status
     */
    private void saveExecLog(DevtApiSubEntity pFunctionsubEntity,Map<String, Object> jsonMap, SqlAndParameters sqlAndParameters, String resultJson,String status,String errorinfo) {

        try{
            DevtApiLogEntity devtApiLogEntity=new DevtApiLogEntity();
            devtApiLogEntity.setCdate(new Timestamp(System.currentTimeMillis()));
            devtApiLogEntity.setEstatus(status);
            devtApiLogEntity.setSubid(pFunctionsubEntity.getId());
            devtApiLogEntity.setJsondata(JSON.toJSONString(jsonMap));
            devtApiLogEntity.setStrsql(sqlAndParameters==null?"":sqlAndParameters.sql);
            devtApiLogEntity.setErrorinfo(errorinfo);
            devtApiLogEntity.setSubdm(pFunctionsubEntity.getDm());
            devtApiLogEntity.setSubname(pFunctionsubEntity.getMc());
            commonApiDao.save(devtApiLogEntity);
        }catch (Exception e){
            log.trace(e.getMessage(),e);
        }
    }

    /**
     *<!--替换拼接就是tjsql里面直接替换#values# sql里面#name#替换tjsql -->
     *<!--预编译就是tjsql里面直接替换#values#后作为预编译SQL参数 sql里面#name#替换? sql配置为and name like #name#  tjsql则为 '%#values#%'-->
     * @param request
     * @param devtApiSubEntity
     * @param jsonMap
     * @return
     */
    private SqlAndParameters getExcuteSql(HttpServletRequest request, DevtApiSubEntity devtApiSubEntity,Map<String, Object> jsonMap) {
        List<DevtApiTjoptEntity> optlist =devtApiTjoptEntityService.getAllDataByIdOrDm(devtApiSubEntity.getId());
        int pageIndex=jsonMap.get("pageIndex")!=null? Integer.parseInt(jsonMap.get("pageIndex").toString()):1;
        int pageSize=jsonMap.get("pageSize")!=null? Integer.parseInt(jsonMap.get("pageSize").toString()):3000;
        
        String value = devtApiSubEntity.getSql();
        if(DevtApiSubEntityService.sqltype.nameprecompile.name().equals(devtApiSubEntity.getSqltype())){
            SqlAndParameters sqlAndParameters = parseOneSqlNamesPreCompile(request, value, optlist, jsonMap);
            sqlAndParameters.pageIndex=pageIndex;
            sqlAndParameters.pageSize=pageSize;
            return sqlAndParameters;
        }else if(DevtApiSubEntityService.sqltype.precompile.name().equals(devtApiSubEntity.getSqltype())){
            SqlAndParameters sqlAndParameters = parseOneSqlPreCompile(request, value, optlist, jsonMap);
            sqlAndParameters.pageIndex=pageIndex;
            sqlAndParameters.pageSize=pageSize;
            return sqlAndParameters;
        }else{
            SqlAndParameters sqlAndParameters = parseOneSql(request,value, optlist, jsonMap);
            sqlAndParameters.pageIndex=pageIndex;
            sqlAndParameters.pageSize=pageSize;
            return sqlAndParameters;
        }
    }

    private SqlAndParameters parseOneSql(HttpServletRequest request,String sql, List<DevtApiTjoptEntity> optlist, Map<String, Object> jsonMap) {

        SqlAndParameters sqlAndParameters = new SqlAndParameters();
        //拼接替换sql
        for (DevtApiTjoptEntity devtApiTjoptEntity : optlist) {
            String argValueOrg = jsonMap.get(devtApiTjoptEntity.getArgname())==null?" ":jsonMap.get(devtApiTjoptEntity.getArgname()).toString();
            sql = sql.replace("#" + devtApiTjoptEntity.getArgname() + "#", argValueOrg);
        }
        sqlAndParameters.sql=Util.replaceDefault(sql,request);
        return sqlAndParameters;
    }

    private SqlAndParameters parseOneSqlNamesPreCompile(HttpServletRequest request,String sql, List<DevtApiTjoptEntity> optlist, Map<String, Object> jsonMap) {
        SqlAndParameters sqlAndParameters = new SqlAndParameters();
        
        LinkedList<Object> valuelinkedList= new LinkedList();
        LinkedList<String> namelinkedList= new LinkedList();
        for (DevtApiTjoptEntity firstLevel : optlist) {
            String argValueOrg = request.getParameter(firstLevel.getArgname());
            String argsPost = StringUtil.isEmptyOrLength0(jsonMap.get(firstLevel.getArgname())) ? "" : jsonMap.get(firstLevel.getArgname()).toString();
            argValueOrg=StringUtil.isEmptyOrLength0(argValueOrg)? argsPost :argValueOrg;
            argValueOrg = StringUtil.isNullOrSpace(argValueOrg) ? "" : StringUtil.unescape(argValueOrg);
            argValueOrg =Util.StrFormat(argValueOrg);
            if (jsonMap.containsKey(firstLevel.getArgname())&&request.getParameter(firstLevel.getArgname())!=null) {
                if (firstLevel.getTjsql().contains("$\\'")) {
                    argValueOrg = argValueOrg.replace("'", "''");
                }
                sql = sql.replace("#" + firstLevel.getArgname() + "#", firstLevel.getTjsql());
                if("Array".equalsIgnoreCase(firstLevel.getCslx())){
                    valuelinkedList.add(Arrays.asList(argValueOrg.split(",")));
                }else{
                    valuelinkedList.add(argValueOrg);
                }
            }else{
                sql = sql.replace("#" + firstLevel.getArgname() + "#"," ");
                valuelinkedList.add("Number".equalsIgnoreCase(firstLevel.getCslx())?null:"");
            }
            namelinkedList.add(firstLevel.getArgname());
        }

        SessionUserInfoEntity sysStaffEntity = RightUtil.getCurrentUser(request);

        namelinkedList.add(DEVTOOLUSER);
        valuelinkedList.add(StringUtil.isEmptyOrLength0(sysStaffEntity.getDevtooluser())?"":sysStaffEntity.getDevtooluser());

        sqlAndParameters.sql=sql;
        sqlAndParameters.parameters=valuelinkedList.toArray();
        sqlAndParameters.parametersNames=namelinkedList.toArray(new String[namelinkedList.size()]);
        return sqlAndParameters;
    }

    private SqlAndParameters parseOneSqlPreCompile(HttpServletRequest request,String sql, List<DevtApiTjoptEntity> optlist, Map<String, Object> jsonMap) {
        SqlAndParameters sqlAndParameters = new SqlAndParameters();

        StringBuilder patternStr=new StringBuilder();
        HashMap<String,DevtApiTjoptEntity> functiontjoptEntityHashMap = new HashMap();
        for (DevtApiTjoptEntity firstLevel : optlist) {
            functiontjoptEntityHashMap.put(firstLevel.getArgname(),firstLevel);
            patternStr.append("#");
            patternStr.append(firstLevel.getArgname());
            patternStr.append("#|");
        }
        patternStr.append(DEVTOOLUSER);
        patternStr.append("|");

        LinkedList<Object> linkedList= new LinkedList();
        Pattern pattern = Pattern.compile(patternStr.toString());
        Matcher matcher=pattern.matcher(sql);
        while(matcher.find()){
            String argnameCofig = matcher.group();
            sql=sql.replaceFirst(argnameCofig, "?");
            matcher=pattern.matcher(sql);

            String argname = argnameCofig.substring(0, argnameCofig.length() - 1).substring(1);
            if(DEVTOOLUSER.equals(argnameCofig)){
                SessionUserInfoEntity sysStaffEntity = RightUtil.getCurrentUser(request);
                linkedList.add( StringUtil.isEmptyOrLength0(sysStaffEntity.getDevtooluser())?"":sysStaffEntity.getDevtooluser());
            }else{
                String argValueOrg = request.getParameter(argname);
                String argsPost = StringUtil.isEmptyOrLength0(jsonMap.get(argname)) ? "" : jsonMap.get(argname).toString();
                argValueOrg=StringUtil.isEmptyOrLength0(argValueOrg)? argsPost :argValueOrg;
                argValueOrg = StringUtil.isNullOrSpace(argValueOrg) ? "" : StringUtil.unescape(argValueOrg);
                argValueOrg =Util.StrFormat(argValueOrg);
                DevtApiTjoptEntity pFunctiontjoptEntity=functiontjoptEntityHashMap.get(argname);
                if (argValueOrg != null) {
                    if (pFunctiontjoptEntity.getTjsql().contains("$\\'")) {
                        argValueOrg = argValueOrg.replace("'", "''");
                    }
                    argValueOrg = pFunctiontjoptEntity.getTjsql().replace("$\\'", "").replace("#values#", argValueOrg);
                    linkedList.add(argValueOrg);
                }else{
                    linkedList.add("Number".equalsIgnoreCase(pFunctiontjoptEntity.getCslx())?null:"");
                }
            }
        }
        sqlAndParameters.sql=sql;
        sqlAndParameters.parameters=linkedList.toArray();
        return sqlAndParameters;
    }

    /**
     * 依据请求参数获取子功能
     * @param p_id
     * @param p_dm
     * @return
     */
    public DevtApiSubEntity getDevtApiSubEntity( String p_id,String p_dm){

            if(!StringUtil.isNullOrSpace(p_id)){
                
                List<DevtApiSubEntity> func_Model=devtApiSubEntityService.getOneData(p_id);
                return func_Model.size()==0?null:func_Model.get(0);
            }

            if(!StringUtil.isNullOrSpace(p_dm)){
                
                List<DevtApiSubEntity> func_Model = devtApiSubEntityService.getOneDataByDm(p_dm);
                return func_Model.size()==0?null:func_Model.get(0);
            }

            return null;
    }
    
    public static class SqlAndParameters{
        public String sql="";
        public Object[] parameters =new Object[0];
        public String[] parametersNames = new String[0];
        public int pageIndex=1;
        public int pageSize=3000;
    }
}

